import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain.agents import tool, AgentExecutor, create_react_agent
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from typing import Tuple

# --- 环境准备 ---
print("正在从 env.example 加载环境变量...")
load_dotenv(dotenv_path="env.example")
api_key = os.getenv("OPENAI_API_KEY")
llm_model_name = os.getenv("OPENAI_MODEL", "qwen-plus-latest")

if not api_key:
    print("错误：请先在 env.example 文件中设置你的 OPENAI_API_KEY。")
else:
    print("环境变量加载成功！")
    # --- Agent 核心流程 ---

    # 1. 定义工具 (Tools) - 改进版
    # 我们修改工具，使其只接受一个字符串参数。
    # 然后在函数内部进行解析，这样能更好地适应某些模型不太规范的输出格式。
    @tool
    def get_rectangle_area(size_str: str) -> float:
        """
        当需要计算长方形面积时，使用此工具。
        输入应该是一个包含宽度和高度的字符串，例如 '(5.5, 10.2)'
        """
        print(f"--- 工具被调用：接收到原始输入 '{size_str}' ---")
        # 移除括号和空格，然后按逗号分割
        try:
            # 去掉可能的括号和空格
            cleaned_str = size_str.strip().strip('()')
            # 按逗号分割
            parts = cleaned_str.split(',')
            if len(parts) != 2:
                return "输入格式错误，应包含两个由逗号分隔的数字。"

            width = float(parts[0].strip())
            height = float(parts[1].strip())
            
            print(f"--- 解析成功：宽={width}, 高={height} ---")
            return width * height
        except Exception as e:
            print(f"--- 解析失败：{e} ---")
            return f"无法解析输入: {size_str}。请确保格式正确，例如 '(5.5, 10.2)'。"

    # 将我们定义的所有工具放入一个列表
    tools = [get_rectangle_area]
    print("1. 工具定义完成。")

    # 2. 创建 Agent 的提示模板
    # 这是一种特殊的模板，需要包含几个关键占位符
    # `input`: 用户的原始输入
    # `agent_scratchpad`: 这是 Agent 的"草稿纸"，用来记录它的思考过程、
    #                     每次调用工具的决策和观察到的结果。
    prompt_template_str = """
    尽你所能回答以下问题。你可以使用以下工具：
    
    {tools}
    
    使用以下格式：
    
    Question: 你必须回答的输入问题
    Thought: 你应该时刻思考该做什么
    Action: 你应该采取的行动，应该是[{tool_names}]中的一个
    Action Input: 对行动的输入
    Observation: 行动的结果
    ...（这个 Thought/Action/Action Input/Observation 的过程可以重复N次）
    Thought: 我现在知道最终答案了
    Final Answer: 对原始输入问题的最终回答
    
    开始！
    
    Question: {input}
    Thought:{agent_scratchpad}
    """
    
    prompt = ChatPromptTemplate.from_template(prompt_template_str)
    print("2. Agent 提示模板已创建。")
    
    # 3. 创建 Agent
    # Agent 本身不是一个链，可以把它理解为"决策核心"或"大脑"。
    # 它负责接收输入，并决定下一步是调用工具还是直接回答。
    # 我们使用 `create_react_agent` 这个函数来创建一个标准的 ReAct 风格的 Agent。
    # ReAct (Reasoning and Acting) 是 Agent 最经典和最可靠的工作模式。
    llm = ChatOpenAI(model=llm_model_name, temperature=0) # Agent 通常需要更稳定的输出，所以 temperature=0
    agent = create_react_agent(llm, tools, prompt)
    print("3. Agent (决策核心) 已创建。")
    
    # 4. 创建 Agent 执行器 (AgentExecutor)
    # AgentExecutor 才是一个完整的、可以运行的链。
    # 它负责执行 Agent 的决策，调用工具，并将结果返回给 Agent，不断循环直到任务完成。
    # `handle_parsing_errors=True`: 这是一个有用的参数，可以处理一些 Agent 输出格式不规范的小问题。
    agent_executor = AgentExecutor(
        agent=agent, 
        tools=tools, 
        verbose=True, # verbose=True 在这里至关重要！让我们能看到 Agent 的完整思考过程。
        handle_parsing_errors=True
    )
    print("4. Agent 执行器已创建。")

    # 5. 运行 Agent！
    print("\n--- 开始与 Agent 交互 ---")

    # 任务：一个需要进行数学计算的问题
    task = "一个长方形的宽是5.5米，高是10.2米，它的面积是多少？"
    print(f"[任务]: {task}")
    response = agent_executor.invoke({"input": task})
    
    print(f"\n[Agent最终回答]: {response['output']}")
    print("\n--- 任务结束 ---") 